package com.bhf.utils;

import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.DeleteByQueryRequest;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * @author pwq
 */
@Component
@Slf4j
public class ElasticsearchUtil {

    @Resource
    private RestHighLevelClient client;

    /**
     * JavaBean形式添加数据
     *
     * @param index
     * @param id
     * @param obj
     * @return
     * @throws IOException
     */
    public boolean addBean(String index, @Nullable String id, Object obj) throws IOException {
        Map<String, Object> objectMap = EntityUtil.beanToMap(obj);
        objectMap.entrySet().removeIf(v -> Objects.isNull(v.getValue()));
        Object empty = objectMap.get("empty");
        if (Objects.nonNull(empty) && !Boolean.parseBoolean(String.valueOf(empty))) {
            return false;
        }
        IndexRequest request = new IndexRequest(index).source(objectMap).id(id);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        return response.getShardInfo().getSuccessful() > 0;
    }

    /**
     * 创建索引
     *
     * @param index    索引
     * @param shards   是数据分片数，默认为5，有时候设置为3
     * @param replicas 是数据备份数，如果只有一台机器，设置为0
     * @param alias    别名
     * @return
     * @throws IOException
     */
    public boolean index(String index, int shards, int replicas, List<String> alias) throws IOException {
        if (existsIndex(index)) {
            return false;
        }
        CreateIndexRequest request = new CreateIndexRequest(index);
        if (alias.size() > 0) {
            alias.forEach(e -> {
                request.aliases().add(new Alias(e));
            });
        }
        request.settings(Settings.builder()
                .put("index.number_of_shards", shards).put("index.number_of_replicas", replicas));
        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    /**
     * 删除索引
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean deleteIndex(String... index) throws IOException {
        if (!existsIndex(index)) {
            return false;
        }
        DeleteIndexRequest request = new DeleteIndexRequest(index);
        AcknowledgedResponse delete = client.indices().delete(request, RequestOptions.DEFAULT);
        return delete.isAcknowledged();
    }

    /**
     * 索引是否存在
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean existsIndex(String... index) throws IOException {
        GetIndexRequest request = new GetIndexRequest(index);
        log.info("source:" + request.toString());
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        log.debug("existsIndex: " + exists);
        return exists;
    }

    /**
     * Map形式添加数据
     *
     * @param index
     * @param id
     * @param map
     * @return
     * @throws IOException
     */
    public boolean addMap(String index, @Nullable String id, Map<String, Object> map) throws IOException {
        IndexRequest request = new IndexRequest(index).source(map).id(id);
        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        return response.getShardInfo().getSuccessful() > 0;
    }

    /**
     * 删除操作
     *
     * @param index
     * @param id
     * @return
     * @throws IOException
     */
    public boolean delete(String index, String id) throws IOException {
        DeleteRequest request = new DeleteRequest(index, id);
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);
        return response.getShardInfo().getSuccessful() > 0;
    }


    /**
     * 根据所选字段删除
     *
     * @param index
     * @param fieldName
     * @param text
     * @return
     * @throws IOException
     */
    public boolean delete(String index, String fieldName, Object text) throws IOException {
        DeleteByQueryRequest request = new DeleteByQueryRequest(index);
        final MatchQueryBuilder matchQueryBuilder = new MatchQueryBuilder(fieldName, text);
        request.setQuery(matchQueryBuilder);
        client.deleteByQuery(request, RequestOptions.DEFAULT);
        return true;
    }

    /**
     * 清空数据库
     *
     * @param index
     * @return
     * @throws IOException
     */
    public boolean delete(String index) throws IOException {
        DeleteByQueryRequest request = new DeleteByQueryRequest(index);
        request.setQuery(QueryBuilders.matchAllQuery());
        client.deleteByQuery(request, RequestOptions.DEFAULT);
        return true;
    }

    /**
     * 更新数据
     *
     * @param index
     * @param id
     * @param obj
     * @return
     * @throws IOException
     */
    public boolean update(String index, String id, Map<String, Object> obj) throws IOException {
        obj.entrySet().removeIf(v -> Objects.isNull(v.getValue()));
        UpdateRequest request = new UpdateRequest(index, id);
        request.doc(obj);
        UpdateResponse update = client.update(request, RequestOptions.DEFAULT);
        return update.getShardInfo().getSuccessful() > 0;
    }
}
